/**
 * Copyright (C) 2010, 2011 by Marco Tupiza.
 *
 * Project Info: http://sourceforge.net/projects/aplilibrary/
 *
 * * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. in the
 * United States and other countries.]
 *
 * --------- Aplinfo Library --------- (C) Copyright 2010-2011, by Aplinfo -
 * Marco V. Tupiza A.
 *
 * Original Author: Marco Tupiza (Aplinfo) Contributor(s): Marcia Conlago
 *
 */
package org.apli.jsf.managed;

import com.apli.controladores.AplinfoFactoryBean;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import org.apli.haiam.ejb.interfaces.AdministradorHaiam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Clase base JsfBean que implementa los métodos genéricos para administrar una
 * página JSF.
 * <p>
 * <H6>Soporte:HAIAM
 * <I>david_s_1086@hotmail.com,david.carranza@haiam.gob.ec</I></H6>
 *
 * @author david Carranza
 * @version 1.0 30/07/2014
 * @param <T> Objeto generico
 */
public abstract class JsfBean<T> implements Serializable {

    final Logger log = LoggerFactory.getLogger(JsfBean.class);
    protected DataModel<T> model;
    protected List<T> lista;
    protected T object;
    @EJB
    protected AdministradorHaiam<T> admin;
    @EJB
    protected AdministradorHaiam adminObject;
    protected static ResourceBundle bundle;

    protected abstract ResourceBundle getProperties();
    //sprotected abstract ResourceBundle getProperties();

    /**
     * Constructor por defecto.
     */
    public JsfBean() {
        if (bundle == null) {
            bundle = ResourceBundle.getBundle("org.apli.jsf.message");
        }
        cargarEjb();
        inicializar();
    }

    /**
     * Inicializa los datos miembros.
     */
    protected abstract void inicializar();

    /**
     * Obtiene el objeto remoto.
     */
    protected void cargarEjb() {
        String nombreMetodo = Thread.currentThread().getStackTrace()[1].getMethodName() + "()";
        if (admin == null) {
            String ejbPath = null;
            try {
                ResourceBundle property = getProperties();
                String ORBContext = property.getString("ORBContext");
                String ejbContextPath = property.getString("ejb.context.path.admin");
                ejbPath = ORBContext + ejbContextPath + "/AdministradorBeanHaiam";
                admin = (AdministradorHaiam<T>) AplinfoFactoryBean.lookupBean(ejbPath, false);
            } catch (Exception e) {
                log.error("{}: {} - {} ", new Object[]{nombreMetodo, ejbPath, e});
            }
        }
        if (adminObject == null) {
            String ejbPath = null;
            try {
                ResourceBundle property = getProperties();
                String ORBContext = property.getString("ORBContext");
                String ejbContextPath = property.getString("ejb.context.path.admin");
                ejbPath = ORBContext + ejbContextPath + "/AdministradorBeanHaiam";
                adminObject = (AdministradorHaiam) AplinfoFactoryBean.lookupBean(ejbPath, false);
            } catch (Exception e) {
                log.error("{}: {} - {} ", new Object[]{nombreMetodo, ejbPath, e});
            }
        }
    }

    /**
     * Graba el registro asociado al objeto que se administra en la página.
     *
     * @return null, se mantiene en la página invocada.
     */
    public abstract String grabarAction();

    /**
     * Implementa el comportamiento para inicializar los datos del objeto a
     * administrar.
     *
     * @return null, retorna a la página invocada.
     */
    public String nuevoAction() {
        inicializar();
        return null;
    }

    public String eliminarAction(T obj) {
        String nombreMetodo = Thread.currentThread().getStackTrace()[1].getMethodName() + "(" + obj.getClass().getSimpleName() + ")";
        FacesContext context = FacesContext.getCurrentInstance();
        try {
            admin.eliminar(obj, FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("user"));
            inicializar();
            cargarLista();
            context.addMessage(findComponent(context.getViewRoot(), "formDatos").getClientId(), new FacesMessage(bundle.getString("msg.eliminar")));
        } catch (Exception e) {
            log.error("{}: {} ", nombreMetodo, e);
            context.addMessage(findComponent(context.getViewRoot(), "formDatos").getClientId(), new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage()));
        }
        return null;

    }

    /**
     * Implementa el comportamiento para seleccionar un elemento en una lista de
     * la página.
     *
     * @return null, se mantiene en la página invocada.
     */
    public String seleccionarAction() {
        T objectTmp = (T) model.getRowData();
        //inicializar();
        object = objectTmp;
        return null;
    }

    public String editarAction(T obj) {
        inicializar();
        object = obj;
        return null;
    }

    /**
     * Carga la lista de objetos en una lista de la página.
     */
    public void cargarDataModel() {
        String nombreMetodo = Thread.currentThread().getStackTrace()[1].getMethodName() + "()";
        if (admin == null) {
            model = null;
            return;
        }
        try {
            model = new ListDataModel(admin.listarOrdenada(object.getClass(), "nombre", true));
        } catch (Exception e) {
            log.error("{}: {} ", nombreMetodo, e);
        }
    }

    /**
     * Carga la lista de objetos en una lista de la página.
     */
    public void cargarLista() {
        String nombreMetodo = Thread.currentThread().getStackTrace()[1].getMethodName() + "()";
        if (admin == null) {
            lista = null;
            return;
        }
        try {
            lista = admin.listarOrdenada(object.getClass(), "nombre", true);
        } catch (Exception e) {
            log.error("{}: {} ", nombreMetodo, e);
        }
    }

    /**
     * Obtiene la lista de objetos .
     *
     * @return el Modelo
     */
    public List<T> getLista() {
        if (lista == null) {
            cargarLista();
        }
        return lista;
    }

    /**
     * Obtiene la lista de objetos en un DataModel.
     *
     * @return el Modelo
     */
    public DataModel<T> getDataModel() {
        if (model == null) {
            cargarDataModel();
        }
        return model;
    }

    /**
     * Obtiene una lista de objetos de tipo SelectedItem.
     *
     * @return la lista
     */
    public abstract List<SelectItem> getSelectedItem();

    /**
     * Busca un componente JSF
     *
     * @param c componente base
     * @param id el id del componente
     * @return el componente buscado
     */
    protected UIComponent findComponent(UIComponent c, String id) {
        if (id.equals(c.getId())) {
            return c;
        }
        Iterator<UIComponent> kids = c.getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent found = findComponent(kids.next(), id);
            if (found != null) {
                return found;
            }
        }
        return null;
    }

    /**
     * Obtiene el objeto que es administrado por la página JSF.
     *
     * @return el objeto
     */
    public T getObject() {
        return object;
    }

    /**
     * Pone el valor del objeto a ser administrado en la página JSF.
     *
     * @param object el objeto
     */
    public void setObject(T object) {
        this.object = object;
    }

    public void valueChangeMethod(AjaxBehaviorEvent event) {
        String nombreMetodo = Thread.currentThread().getStackTrace()[1].getMethodName() + "()";
        log.debug("{} evento {}", nombreMetodo, event);
    }
}
